package org.banxico.ds.sisal.servlets;

import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.banxico.ds.sisal.dao.SoftwareDAO;
import org.banxico.ds.sisal.dao.VulnerabilityDAO;
import org.banxico.ds.sisal.entities.Software;
import org.banxico.ds.sisal.parser.entidades.CVE;
import org.banxico.ds.sisal.parser.entidades.CVEReference;
import org.banxico.ds.sisal.parser.entidades.VulnSoftware;

/**
 * Controlador para la lista de Vulnerabilidades y de Software
 *
 * @author t41507
 * @version 04072014
 */
public class VulnerabilityServlet extends HttpServlet implements java.io.Serializable {

    /**
     * Atributos de serialización y Logger
     */
    private static final long serialVersionUID = -1L;
    private static final Logger LOG = Logger.getLogger(VulnerabilityServlet.class.getName());
    /**
     * Atributos del Servlet
     */
    private VulnerabilityDAO vulndao;

    /**
     * Constructor
     */
    public VulnerabilityServlet() {
        super();
    }

    /**
     * Método doGet
     *
     * @param request referencia de Solicitud
     * @param response referencia de Respuesta
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        ServletContext context = this.getServletContext();
        //LOG.log(Level.INFO, "El directorio de lectura será; {0}", path.toString());
        //Verificar que el parametro action no sea nulo
        vulndao = new VulnerabilityDAO();
        if (!request.getParameter("action").equals("")) {
            //Solicitar el párametro action
            String action = (String) request.getParameter("action");
            //Atributos del paginador
            int page = 1;
            int recordsPerPage = 20;
            String nextJSP = "/admin/Index.html";
            //Instancia del request dispatcher
            RequestDispatcher view;
            //Instanciar los daos de vulnerabilidad y software y almacenarlos en sesion
            //VulnerabilityDAO vulndao = new VulnerabilityDAO();
            SoftwareDAO swdao = new SoftwareDAO();
            HttpSession sesion = request.getSession();
            try {
                sesion.setAttribute("vulndao", vulndao);
                sesion.setAttribute("swdao", swdao);
            } catch (ClassCastException e) {
                LOG.log(Level.INFO, "Ocurrio un error al intentar almacenar los daos en sesion.");
            }
            //Si el parametro action es view
            if (action.equalsIgnoreCase("view")) {
                //Solicitar el parametro tipo
                String tipo = (String) request.getParameter("tipo");
                int tipoI = Integer.parseInt(tipo);
                switch (tipoI) {
                    //Caso 1 vulnerabilidades recientes
                    case 1:
                        //Solicitar la pagina
                        if (request.getParameter("page") != null) {
                            page = Integer.parseInt(request.getParameter("page"));
                        }
                        //Obtener la lista de vulnerabilidades recientes de acuerdo a la pagina y cantidad de registros
                        List<CVE> cveList = vulndao.obtenerDeRecientes((page - 1) * recordsPerPage, recordsPerPage);
                        //Obtener total de registros y de paginas
                        int noOfRecords = vulndao.obtenerCantidadRecientes();
                        int noOfPages = (int) Math.ceil(noOfRecords * 1.0 / recordsPerPage);
                        //Establecer los elementos como atributos
                        request.setAttribute("cveList", cveList);
                        request.setAttribute("noOfPages", noOfPages);
                        request.setAttribute("currentPage", page);
                        request.setAttribute("totalr", noOfRecords);
                        //Establecer la redirección
                        nextJSP = "/admin/vulnerabilities/recentVulns.jsp";
                        break;
                    //Caso 2 archivo de vulnerabilidades
                    case 2:
                        //Solicitar la pagina
                        if (request.getParameter("page") != null) {
                            page = Integer.parseInt(request.getParameter("page"));
                        }
                        //Obtener la lista del archivo de acuerdo a la pagina y cantidad de registros
                        List<CVE> arcveList = vulndao.obtenerDeArchivo((page - 1) * recordsPerPage, recordsPerPage);

                        //Obtener total de registros y de paginas
                        int arnoOfRecords = vulndao.obtenerCantidadArchivo();
                        int arnoOfPages = (int) Math.ceil(arnoOfRecords * 1.0 / recordsPerPage);
                        //Establecer los elementos como atributos
                        request.setAttribute("arcveList", arcveList);
                        request.setAttribute("arnoOfPages", arnoOfPages);
                        request.setAttribute("currentPage", page);
                        request.setAttribute("total", arnoOfRecords);
                        //Establecer la redirección
                        nextJSP = "/admin/vulnerabilities/vulnArchive.jsp";
                        break;
                    // Caso 3 software registrado
                    case 3:
                        //Solicitar la pagina
                        if (request.getParameter("page") != null) {
                            page = Integer.parseInt(request.getParameter("page"));
                        }
                        //Obtener la lista de sw de acuerdo a la pagina y cantidad de registros
                        LOG.log(Level.INFO, "Traera los registros entre: {0} y {1}", new Object[]{(page - 1) * recordsPerPage, recordsPerPage});
                        List<Software> swList = swdao.retrieveFromLimit((page - 1) * recordsPerPage, recordsPerPage);
                        //Obtener total de registros y paginas
                        int swnoOfRecords = swdao.obtenerNumeroRegistros();
                        int swnoOfPages = (int) Math.ceil(swnoOfRecords * 1.0 / recordsPerPage);
                        //Establecer los elementos como atributos
                        request.setAttribute("swList", swList);
                        request.setAttribute("swnoOfPages", swnoOfPages);
                        request.setAttribute("currentPage", page);
                        //Establecer la redirección
                        nextJSP = "/admin/vulnerabilities/supportedSW.jsp";
                        break;
                }
                //Realizar la redirección
                view = getServletContext().getRequestDispatcher(nextJSP);
                view.forward(request, response);
                //Caso edición
            } else if (action.equalsIgnoreCase("edit")) {

            } else if (action.equalsIgnoreCase("search")) {
                //Caso busqueda
                response.setContentType("text/html; charset=UTF-8");
                //Solicitar el parametro tipo
                String type = request.getParameter("type");
                //Crear un buffer
                StringBuilder bf = new StringBuilder();
                //Si el tipo de busqueda es de software
                if (type.equalsIgnoreCase("swsearch")) {
                    //Solicitar el parametro keyu
                    String key = request.getParameter("key");
                    //Realizar la busqueda y generar la presentación con el buffer
                    List<Software> foundSw = swdao.searchSoftware(key);
                    for (Software sw : foundSw) {
                        bf.append("<tr>");
                        bf.append("<td style='width: 150px;'>")
                                .append(sw.getFabricante())
                                .append("</td>");
                        bf.append("<td style='width: 240px;'>")
                                .append(sw.getNombre())
                                .append("</td>");
                        bf.append("<td style='width: 80px; text-align: center;'>")
                                .append(sw.getVersion())
                                .append("</td>");
                        bf.append("<td>");
                        bf.append("<a class='view' onclick='eliminarSoftware(")
                                .append(sw.getIdSoftware())
                                .append(",")
                                .append("\"")
                                .append(sw.getNombre())
                                .append("\"")
                                .append(")'>")
                                .append("<img class='delbtn' id='tableicon' alt='id=")
                                .append(sw.getIdSoftware())
                                .append("' src='/sisalbm/resources/images/trash.png' />")
                                .append("</a>");
                        /*
                        int eol = sw.getEndoflife();
                        switch (eol) {
                            case 0:
                                bf.append("No");
                                break;
                            case 1:
                                bf.append("Si");
                                break;
                            case -1:
                                bf.append("ND");
                                break;
                            default:
                                bf.append("ND");
                                break;
                        }
                        */
                        bf.append("</td>");
                        bf.append("</tr>");
                    }
                    //Si el tipo de busqueda es vulnerabilidad
                } else if (type.equalsIgnoreCase("vulnsearch")) {
                    //Solicitar el parametro keyu
                    String key = request.getParameter("key");
                    //Realizar la busqueda de vulnerabilidades y realizar la presentación
                    List<CVE> foundList = vulndao.searchCVE(key);
                    //Si no encuentra nada retornar un mensaje, en otro caso retornar el código html con los resultados
                    if (foundList.isEmpty()) {
                        bf.append("notfound");
                    } else {
                        for (CVE cve : foundList) {
                            SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
                            bf.append("<tr>");
                            bf.append("<td>").append(cve.getName()).append("</td>\n");
                            bf.append("<td>").append(formatter.format(cve.getPublished())).append("</td>\n");
                            bf.append("<td>").append(formatter.format(cve.getModified())).append("</td>\n");
                            bf.append("<td>").append(cve.getCVSS().getScore()).append("</td>\n");
                            String sev = "";
                            if (cve.getSeverity().equalsIgnoreCase("high")) {
                                sev = "Alta";
                            } else if (cve.getSeverity().equalsIgnoreCase("medium")) {
                                sev = "Media";
                            } else if (cve.getSeverity().equalsIgnoreCase("low")) {
                                sev = "Baja";
                            } else {
                                sev = "ND";
                            }
                            bf.append("<td>")
                                    .append(sev)
                                    .append("</td>\n");
                            bf.append("</tr>");
                            bf.append("<tr>");
                            bf.append("<td>Impacto:</td>");
                            bf.append("<td colspan='4'>");
                            if (!cve.getCVSS().vector.toString().equals("") && !cve.getCVSS().vector.equals("ND")) {
                                bf.append(vulndao.describirVector(cve.getCVSS().getVector()));
                            } else {
                                bf.append("<p id='cvssvector'>Vector No Disponible</p>");
                            }
                            bf.append("</td>");
                            bf.append("</tr>");
                            bf.append("<tr>");
                            bf.append("<td>Descripción:</td>");
                            bf.append("<td colspan='4'>").append(cve.getDescription()).append("</td>");
                            bf.append("</tr>");
                            bf.append("<tr>");
                            bf.append("<td>Software Vulnerable:</td>");
                            bf.append("<td colspan='4'>");
                            bf.append("<table style='border:none'>");
                            bf.append("<tr>").append("<td>Fabricante</td><td>Software</td><td colspan='2'>Versi&oacute;n(es)</td></tr>");
                            for (VulnSoftware sw : cve.getVuln_soft()) {
                                bf.append("<tr>");
                                bf.append("<td>").append(sw.getVendor().toUpperCase()).append("</td>");
                                bf.append("<td>").append(sw.getName().toUpperCase()).append("</td>");
                                bf.append("<td colspan='3'>").append(sw.getVersion().toString()).append("</td>");
                                bf.append("</tr>");
                            }
                            bf.append("</table>");
                            bf.append("</td>");
                            bf.append("</tr>");
                            bf.append("<tr>");
                            bf.append("<td>Referencias:</td>");
                            bf.append("<td colspan='4'>");
                            bf.append("<table style='border:none'>");
                            for (CVEReference ref : cve.getReferences()) {
                                bf.append("<tr>");
                                bf.append("<td>").append(ref.getSource()).append("</td>");
                                bf.append("<td>").append("<a href='").append(ref.getUrl()).append("' target='_blank'>").append(ref.getUrl()).append("</a>").append("</td>");
                                bf.append("</tr>");
                            }
                            bf.append("</table>");
                            bf.append("</td>");
                            bf.append("</tr>");
                        } //foreach
                    }//else
                }
                //Escribir la respuesta en el flujo
                response.getWriter().write(bf.toString());
                //Si action es igual a ADD
            } else if (action.equalsIgnoreCase("add")) {
                //1 para SRC 2 para SW
                //Obtener el tipo
                String tipo = (String) request.getParameter("tipo");
                if (tipo.equalsIgnoreCase("1")) {
                    LOG.log(Level.INFO, "Agregar Fuente");
                } else if (tipo.equalsIgnoreCase("2")) {
                    //Obtener los parametros ingresados
                    String fabricante = request.getParameter("fabricante");
                    //return original.substring(0, 1).toUpperCase() + original.substring(1);
                    fabricante = fabricante.substring(0, 1).toUpperCase() + fabricante.substring(1);
                    String nombre = request.getParameter("nombre");
                    nombre = nombre.substring(0, 1).toUpperCase() + nombre.substring(1);
                    String version = request.getParameter("version");
                    //Solicitar parametro grupo
                    String agrupo = request.getParameter("grupo");
                    //Si se va a añadir solicitar cantidad y pedir parametros
                    int[] llavegrupos = null;
                    if (agrupo.equalsIgnoreCase("si")) {
                        String total = request.getParameter("total");
                        int itotal = Integer.parseInt(total);
                        llavegrupos = new int[itotal];
                        for (int i = 0; i < itotal; i++) {
                            llavegrupos[i] = Integer.parseInt(request.getParameter("grupo" + i));
                        }
                        Arrays.sort(llavegrupos);
                    }
                    Software addsw;
                    boolean insercion = false;
                    String nombresw = fabricante + " " + nombre + " " + version;
                    addsw = new Software(0, fabricante, nombresw, version, 1, -1, "ND", "ND");
                    boolean existencia = swdao.validarExistencia(addsw);
                    if (!existencia) {
                        //Agregar
                        if (agrupo.equalsIgnoreCase("si")) {
                            try {
                                insercion = swdao.agregarSoftware_enGrupos(addsw, llavegrupos);
                            } catch (SQLException ex) {
                                LOG.log(Level.INFO, "VulnerabilityServlet#agregarSoftware() - Ocurrio un problema al realizar la transacci\u00f3n: {0}", ex.getMessage());
                            }
                        } else if (agrupo.equalsIgnoreCase("no")) {
                            insercion = swdao.agregarSoftware(addsw);
                        }
                    }

                    response.setContentType("text/html; charset=UTF-8");
                    if (existencia) {
                        response.getWriter().write("EXISTENTE");
                    } else if (insercion) {
                        response.getWriter().write("OK");
                    } else if (!insercion) {
                        response.getWriter().write("NOT");
                    } else {
                        response.getWriter().write("ERROR");
                    }
                }
            }
        }
    }

    /**
     * Método doPost
     *
     * @param req referencia de Solicitud
     * @param resp referencia de Respuesta
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

}


/**
 * RESPALDO AGREGAR SOFTWAREW
 
 //Obtener los parametros ingresados
                    String fabricante = request.getParameter("fabricante");
                    //return original.substring(0, 1).toUpperCase() + original.substring(1);
                    fabricante = fabricante.substring(0, 1).toUpperCase() + fabricante.substring(1);
                    String nombre = request.getParameter("nombre");
                    nombre = nombre.substring(0, 1).toUpperCase() + nombre.substring(1);
                    String version = request.getParameter("version");
                    
                    String tipoSW = request.getParameter("tipo");
                    String eol = request.getParameter("eol");
                    int fdv = 0;
                    switch (Integer.parseInt(eol)) {
                        case 1: //si
                            fdv = 1;
                            break;
                        case 2: //no
                            fdv = 0;
                            break;
                        default:
                            fdv = -1;
                            break;
                    }
                    //Crear el nuevo objeto sw y crearlo con el dao
                    Software addSw = new Software(0, fabricante, fabricante + " " + nombre + " " + version, version, Integer.parseInt(tipoSW), fdv, "ND", "ND");
                    boolean flag = swdao.agregarSoftware(addSw);
                    //response.setContentType("text/plain");
                    response.setContentType("text/html; charset=UTF-8");
                    
                    if (flag) {
                        response.getWriter().write("OK");
                    } else if (!flag) {
                        response.getWriter().write("NOT");
                    } else {
                        response.getWriter().write("ERROR");
                    }
*/
